#include once <alloc.asm>
#include once <strlen.asm>
;
__ADDSTR:	; Implements c$ = a$ + b$
; hl = &a$, de = &b$ (pointers)
;
__STRCAT2:	; This routine creates a new string in dynamic space
; making room for it. Then copies a$ + b$ into it.
; HL = a$, DE = b$
                     ;- PROC
                     ;- LOCAL __STR_CONT
                     ;- LOCAL __STRCATEND
lda z80_l            ;- push hl
pha
lda z80_h
pha
jsr __STRLEN         ;- call __STRLEN
lda z80_l            ;- ld c,l
sta z80_c
                     ;- ld b, h		; BC = LEN(a$)
                     ;- ex (sp), hl ; (SP) = LEN (a$), HL = a$
                     ;- push hl		; Saves pointer to a$
                     ;- inc bc
                     ;- inc bc		; +2 bytes to store length
                     ;- ex de, hl
lda z80_l            ;- push hl
pha
lda z80_h
pha
jsr __STRLEN         ;- call __STRLEN
; HL = len(b$)
                     ;- add hl, bc	; Total str length => 2 + len(a$) + len(b$)
lda z80_l            ;- ld c,l
sta z80_c
                     ;- ld b, h		; BC = Total str length + 2
jsr __MEM_ALLOC      ;- call __MEM_ALLOC
                     ;- pop de		; HL = c$, DE = b$
lda z80_e            ;- ex de,hl	; HL = b$, DE = c$
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
                     ;- ex (sp), hl ; HL = a$, (SP) = b$
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop de		; D'E' = b$
sta z80_d
pla
sta z80_e
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop bc		; LEN(a$)
sta z80_b
pla
sta z80_c
lda z80_d            ;- ld a,d
sta z80_a
ora z80_e            ;- or e
                     ;- ret z		; If no memory: RETURN

__STR_CONT:
lda z80_e            ;- push de		; Address of c$
pha
lda z80_d
pha
lda z80_h            ;- ld a,h
sta z80_a
ora z80_l            ;- or l
jne __STR_CONT1      ;- jr nz, __STR_CONT1 ; If len(a$) != 0 do copy
; a$ is NULL => uses HL = DE for transfer
lda z80_d            ;- ld h,d
sta z80_h
lda z80_e            ;- ld l,e
sta z80_l
                     ;- ld (hl),a	  ; This will copy 00 00 at (DE) location
inc z80_e            ;- inc de
bne *+4
inc z80_d
                     ;- dec bc      ; Ensure BC will be set to 1 in the next step

__STR_CONT1:         ; Copies a$ (HL) into c$ (DE)
inc z80_c            ;- inc bc
bne *+4
inc z80_b
inc z80_c            ;- inc bc		; BC = BC + 2
bne *+4
inc z80_b
                     ;- ldir		; MEMCOPY: c$ = a$
pla                  ;- pop hl		; HL = c$
sta z80_h
pla
sta z80_l
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
lda z80_e            ;- push de		; Recovers b$; A ex hl,hl' would be very handy
pha
lda z80_d
pha
lda z80_c            ;- exx
ldx z80_cp
stx z80_c
sta z80_cp
lda z80_b
ldx z80_bp
stx z80_b
sta z80_bp
lda z80_e
ldx z80_ep
stx z80_e
sta z80_ep
lda z80_d
ldx z80_dp
stx z80_d
sta z80_dp
lda z80_l
ldx z80_lp
stx z80_l
sta z80_lp
lda z80_h
ldx z80_hp
stx z80_h
sta z80_hp
pla                  ;- pop de		; DE = b$
sta z80_d
pla
sta z80_e

__STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$
; NOTE: Both DE, BC and AF are modified and lost
; Returns HL (pointer to a$)
; a$ Must be NOT NULL
lda z80_d            ;- ld a,d
sta z80_a
ora z80_e            ;- or e
bne *+3              ;- ret z		; Returns if de is NULL (nothing to copy)
rts
lda z80_l            ;- push hl		; Saves HL to return it later
pha
lda z80_h
pha
ldy #$00             ;- ld c,(hl)
lda (z80_hl),y
sta z80_c
inc z80_l            ;- inc hl
bne *+4
inc z80_h
ldy #$00             ;- ld b,(hl)
lda (z80_hl),y
sta z80_b
inc z80_l            ;- inc hl
bne *+4
inc z80_h
lda z80_l            ;- add hl,bc	; HL = end of (a$) string ; bc = len(a$)
clc
adc z80_c
sta z80_l
lda z80_h
adc z80_b
sta z80_h
lda z80_c            ;- push bc		; Saves LEN(a$) for later
pha
lda z80_b
pha
lda z80_e            ;- ex de,hl	; DE = end of string (Begin of copy addr)
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
ldy #$00             ;- ld c,(hl)
lda (z80_hl),y
sta z80_c
inc z80_l            ;- inc hl
bne *+4
inc z80_h
ldy #$00             ;- ld b,(hl)	; BC = len(b$)
lda (z80_hl),y
sta z80_b
lda z80_b            ;- ld a,b
sta z80_a
ora z80_c            ;- or c
                     ;- jr z, __STRCATEND; Return if len(b$) == 0
lda z80_c            ;- push bc			 ; Save LEN(b$)
pha
lda z80_b
pha
inc z80_l            ;- inc hl			 ; Skip 2nd byte of len(b$)
bne *+4
inc z80_h
                     ;- ldir			 ; Concatenate b$
pla                  ;- pop bc			 ; Recovers length (b$)
sta z80_b
pla
sta z80_c
pla                  ;- pop hl			 ; Recovers length (a$)
sta z80_h
pla
sta z80_l
lda z80_l            ;- add hl, bc		 ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$)
clc
adc z80_c
sta z80_l
lda z80_h
adc z80_b
sta z80_h
lda z80_e            ;- ex de,hl		 ; DE = LEN(a$+b$)
ldx z80_l
stx z80_e
sta z80_l
lda z80_d
ldx z80_h
stx z80_d
sta z80_h
pla                  ;- pop hl
sta z80_h
pla
sta z80_l
lda z80_e            ;- ld (hl),e		 ; Updates new LEN and return
ldy #$00
sta (z80_hl),y
inc z80_l            ;- inc hl
bne *+4
inc z80_h
lda z80_d            ;- ld (hl),d
ldy #$00
sta (z80_hl),y
                     ;- dec hl
rts                  ;- ret

__STRCATEND:
pla                  ;- pop hl		; Removes Len(a$)
sta z80_h
pla
sta z80_l
pla                  ;- pop hl		; Restores original HL, so HL = a$
sta z80_h
pla
sta z80_l
rts                  ;- ret
                     ;- ENDP

